42 import scipy.optimize
as scop
43 from math
import log10, pi, atan2, sqrt, floor
46 from template
import fileTemplate
50 np.seterr(divide=
'ignore')
62 parameterDict = {
'outName':
'outName',
'outDir':
'outDir',
'outDirName':
'outDirName',
'N':
'N',
'f0':
'f0',
'BW':
'BW',
63 'filterTransferFunc':
'filterTransferFunc',
'chebyLr':
'chebyLr',
'qeZero':
'qeZero' ,
'qeLr':
'qeLr',
64 'transImagZeros':
'transImagZeros',
'transComplexZeros':
'transComplexZeros',
'genChebyLr':
'genChebyLr',
65 'genChebyLP':
'genChebyLP',
'LPalgor' :
'LPalgor',
'LPmaxIter' :
'LPmaxIter',
'LPNsamples' :
'LPNsamples',
66 'LPcomplexZeros':
'LPcomplexZeros',
'LPrealZeros':
'LPrealZeros',
'LPfracBW':
'LPfracBW',
'LPripple':
'LPripple',
67 'synthTech':
'synthTech',
'zerosArrang':
'zerosArrang',
'adapPredis':
'adapPredis',
'Qef':
'Qef',
'wFunc':
'wFunc',
68 'finiteQo':
'finiteQo',
'Qo':
'Qo',
'QoPredis':
'QoPredis',
69 'nuqK':
'nuqK',
'nuqK11c1':
'nuqK11c1',
'nuqK22c1':
'nuqK22c1',
'nuqK21c1':
'nuqK21c1',
'nuqK21c2':
'nuqK21c2',
'nuqK21c3':
'nuqK21c3',
70 'nuqTech':
'nuqTech',
'nuqDelta':
'nuqDelta',
71 'maxFreq':
'maxFreq',
'minFreq':
'minFreq',
'numFreq':
'numFreq' }
75 saveSignificantDigits = 14
80 saveSignificantDigitsEnergy = 4
132 _cfunc_complex = np.vectorize(complex)
160 for key, value
in variablesDict.items():
161 globals()[key] = value
181 pkgname = re.search(
'@package (.*)', st).group(1)
182 version = re.search(
'@version (.*)', st).group(1)
183 return(pkgname, version)
195 st = re.sub(
'<[^>]*?>',
'', st)
197 if mainWindow
is not None:
199 if platform.system()
in [
'Windows',
'Microsoft',
'Vista' ]: st = st.replace(
'\r\n',
'\n')
204 mainWindow.log_listWidget.addItem(unicode(st))
205 mainWindow.log_listWidget.setCurrentRow(mainWindow.log_listWidget.count()-1)
209 if hasattr(sys.stdout,
'encoding')
and sys.stdout.encoding
in [
None,
'ascii']:
211 st =
''.join(map(
lambda c: c
if ord(c)<128
else '?', st ))
226 st =
'Successfully imported: %s; version %s\n' %
pkgNameVersion(st)
228 st =
u"\n%s\n%s" % (applicationName, st)
229 st = st.replace(
'@package',
'Package')
230 st = st.replace(
'@author',
'Authors:')
231 st = st.replace(
'@date',
'Date:')
232 st = st.replace(
'@version',
'Version:')
233 st = st.replace(
'<p>',
'\n')
234 st = st.replace(
'<br>',
'\n')
235 st = st.replace(
'©',
'(c)')
236 st =
"""%s \nPython %s on %s \n""" % (st, platform.python_version(), platform.system())
241 if mainWindow
is None and not nogui:
243 preGuiOutput = preGuiOutput + st
258 for codec
in [
'utf-8',
'iso8859_15']:
260 myPrint(
'Openning file: %s' % os.path.basename(fileName))
261 file = codecs.open(fileName,
'r', codec)
263 raise parseError,
'I/O error: %s' % err
266 stList = file.readlines()
268 except UnicodeDecodeError, err:
270 myPrint(
"Cannot open file with encoding '%s'" % (codec))
272 myPrint(
"File sucessfully opened with encoding '%s'" % (codec))
276 myPrint(
'Reading parameters from file: %s' % os.path.basename(fileName))
279 except parseError, err:
291 if mainWindow
is not None:
292 QMessageBox.critical(mainWindow,
"%s" % mainWindow.applicationName, st)
296 if mainWindow.SPlotMagPhase
is not None and not mainWindow.SPlotMagPhase.closed:
297 mainWindow.SPlotMagPhase.close()
298 mainWindow.SPlotMagPhase =
None
299 if mainWindow.SPlotError
is not None and not mainWindow.SPlotError.closed:
300 mainWindow.SPlotError.close()
301 mainWindow.SPlotError =
None
304 st = st.replace(
'<p>',
'\n')
305 st = st.replace(
'<br>',
' ')
306 st = re.sub(
'<[^>]*?>',
'', st)
317 if mainWindow
is not None:
318 QMessageBox.warning(mainWindow,
"%s" % mainWindow.applicationName, st)
320 st = st.replace(
'<p>',
'\n')
321 st = st.replace(
'<br>',
' ')
322 st = st.replace(
'<b>',
'* ')
323 st = st.replace(
'</b>',
' *')
333 if mainWindow
is not None:
334 QMessageBox.information(mainWindow,
"%s" % mainWindow.applicationName, st)
336 st = st.replace(
'<p>',
'\n')
337 st = st.replace(
'<br>',
' ')
349 if mainWindow
is not None:
350 return QMessageBox.question(mainWindow,
"%s" % mainWindow.applicationName, st, buttons)
364 for x
in listX: st +=
'%.*g, ' % (prec, x)
365 return st[0:len(st)-2] +
']'
386 def complexStr(x, prec, format=None, minWidth=0, eng = False, listFormat = False):
388 re, im = np.real(x), np.imag(x)
393 reExp = int(3*floor(log10(abs(re))/3))
if re != 0
else 0
394 re = re / pow(10, reExp)
399 stReExp =
'e' + str(reExp)
if reExp != 0
else ''
403 imExp = int(3*floor(log10(abs(im))/3))
if im != 0
else 0
404 im = im / pow(10, imExp)
409 stImExp =
'e' + str(imExp)
if imExp != 0
else ''
412 stReExp, stImExp =
'',
''
414 reim = abs(re/im)
if abs(im) > 0
else np.inf
415 imre = abs(im/re)
if abs(re) > 0
else np.inf
418 st1 =
'%+.*g%s' % (prec, re, stReExp)
if min(abs(re), reim) > 10**-prec
else ''
419 st2 =
'%+.*g%sj' % (prec, im, stImExp)
if min(abs(im), imre) > 10**-prec
else ''
421 st1 =
'%-+*.*g%s' % (minWidth, prec, re, stReExp)
if min(abs(re), reim) > 10**-prec
else '%-*s' % (minWidth,
'0')
422 st2 =
' %-+*.*g%s' % (minWidth, prec, im, stImExp)
if min(abs(im), imre) > 10**-prec
else ' %-*s' % (minWidth,
'0')
423 st2 = st2.replace(
'+',
' ')
425 mag, angle = abs(x), (180/pi)*atan2(np.imag(x), np.real(x))
426 st1 =
'%-+*.*g' % (minWidth, prec, mag)
if abs(mag) > 10**-prec
else '%-*s' % (minWidth,
'0')
427 st2 =
' %-+*.*g' % (minWidth, prec, angle)
if abs(angle) > 10**-prec
else ' %-*s' % (minWidth,
'0')
433 mag, angle = 20*log10(abs(x)), (180/pi)*atan2(np.imag(x), np.real(x))
434 st1 =
'%-+*.*g' % (minWidth, prec, mag)
if abs(mag) > 10**-prec
else '%-*s' % (minWidth,
'0')
435 st2 =
' %-+*.*g' % (minWidth, prec, angle)
if abs(angle) > 10**-prec
else ' %-*s' % (minWidth,
'0')
437 if listFormat ==
False:
438 st =
'%-*s' % (minWidth, st1 + st2)
439 if len(st)==0: st =
'0'
440 if st[0]==
'+': st =
' ' + st[1:len(st)]
471 if stValue.endswith(
'\n'): stValue = stValue[:-1]
474 if stValue.lstrip() ==
'':
return None
477 stValue = stValue.split(
',')
481 if type ==
'int': n = [ int(elem)
for elem
in stValue ]
482 elif type ==
'float': n = [ np.inf
if elem.lower().lstrip().rstrip()==
'inf' else float(elem)
for elem
in stValue ]
483 elif type ==
'complex': n = [ complex(elem)
for elem
in stValue ]
484 elif type ==
'string': n = [ unicode(elem.lstrip().rstrip(),
'utf-8')
for elem
in stValue ]
485 else:
raise parseError,
"Bad [%s] parameter type: '%s' " % (key, type)
486 except ValueError, err:
487 raise parseError,
"Bad [%s] parameter format: '%s' " % (key, err)
490 if len(n) == 1: n = n[0]
506 if stList
is not None:
509 validLines = [ st
for st
in stList
if st.find(
'=') >=0
and not st.startswith(
'#') ]
511 pat = re.compile(
'^.*\[(.+)\].*\{(.+)\}.*=(.+)$')
512 matchList = [ pat.match(line)
for line
in validLines ]
514 if matchList[0]
is None:
515 myPrint(
"Reading Chebash file format")
516 pat = re.compile(
'^(.+)=(.+)$')
517 matchList = [ pat.match(line)
for line
in validLines ]
521 myPrint(
"Reading LossyFilters file format")
522 chebashFormat =
False
525 paramList = [ match.groups(1)
for match
in matchList
if match
is not None]
531 for (key, type, value)
in paramList:
534 value = value.replace(
'\\',
'\\\\').strip()
535 command =
"self.%s = self.readParam('%s', '%s', '%s')" % ( parameterDict[key], key, type, value )
537 except KeyError:
raise parseError,
u"Invalid keyword: '%s'" % key
540 for field
in parameterDict.values():
541 if field
not in dir(self): exec
"self.%s = None" % field
564 for key
in parameterDict.values():
565 command =
"self.%s = None" % key
603 if paramList[0][0] ==
'n': self.
N = int(paramList[0][1])
604 else:
raise parseError,
u"parameter 'n' missing or misplaced in Chebash file"
606 if paramList[1][0] ==
'fo': self.f0 = float(paramList[1][1]) * 1e6
607 else:
raise parseError,
u"parameter 'fo' missing or misplaced in Chebash file"
609 if paramList[2][0] ==
'Qo': self.Qo = float(paramList[2][1])
610 else:
raise parseError,
u"parameter 'Qo' missing or misplaced in Chebash file"
612 if paramList[3][0] ==
'wp': self.BW = float(paramList[3][1]) * 1e6
613 else:
raise parseError,
u"parameter 'wp' missing or misplaced in Chebash file"
615 if paramList[4][0] ==
'ro': self.genChebyLr = float(paramList[4][1])
616 else:
raise parseError,
u"parameter 'ro' missing or misplaced in Chebash file"
618 if paramList[5][0] ==
'puntos': self.numFreq = int(paramList[5][1])
619 else:
raise parseError,
u"parameter 'puntos' missing or misplaced in Chebash file"
621 if paramList[6][0] ==
'n_ceros': n_ceros = int(paramList[6][1])
622 else:
raise parseError,
u"parameter 'n_ceros' missing or misplaced in Chebash file"
625 if paramList[7][0] ==
'ceros': self.
transImagZeros = [ self.f0 + float(st)*1e6
for st
in paramList[7][1].split(
',') ]
626 else:
raise parseError,
u"parameter 'ceros' missing or misplaced in Chebash file"
627 if len(self.
transImagZeros) != n_ceros:
raise parseError,
u"Incorrect number of transmission zeros in Chebash file"
631 if paramList[8][0] ==
'n_ceros_eq': n_ceros_eq = int(paramList[8][1])
632 else:
raise parseError,
u"parameter 'n_ceros_eq' missing or misplaced in Chebash file"
636 if paramList[9][0] ==
'real': realEqZs = [ float(st)
for st
in paramList[9][1].split(
',') ]
637 else:
raise parseError,
u"parameter 'real' (for equalization ceros) missing or misplaced in Chebash file"
639 if paramList[10][0] ==
'imag': imagEqZs = [ self.f0 + float(st)*1e6
for st
in paramList[10][1].split(
',') ]
640 else:
raise parseError,
u"parameter 'imag' (for equalization ceros) missing or misplaced in Chebash file"
642 self.
transComplexZeros = [ complex(val[0],val[1])
for val
in zip(realEqZs, imagEqZs) ]
643 if len(self.
transComplexZeros) != n_ceros_eq:
raise parseError,
u"Incorrect number of equalization zeros in Chebash file"
650 for TZ
in self.transComplexZeros:
651 if -TZ.conjugate()
not in nonSymmZeros: nonSymmZeros.append(TZ)
652 self.transComplexZeros = nonSymmZeros
655 self.outName =
'Chebash'
657 self.filterTransferFunc =
'Generalized Chebyshev'
659 self.synthTech =
'Minimum Insertion Loss'
661 self.nuqTech =
'kS21+kS11'
662 self.minFreq = self.f0 - 3*self.BW
663 self.maxFreq = self.f0 + 3*self.BW
737 if not isinstance(self.outName, types.StringTypes)
or len(self.outName) == 0:
738 raise parseError,
u"Name of results output files is not a valid string"
757 if self.filterTransferFunc.title()
not in [
u'Butterworth',
u'Chebyshev',
u'Quasieliptic',
u'Generalized Chebyshev' ]:
758 raise parseError,
u"Invalid filter topology type '%s'" % self.filterTransferFunc
760 if self.synthTech.title()
not in [
u'Minimum Insertion Loss',
u'Predistortion',
u'Prescribed Insertion Loss' ]:
761 raise parseError,
u"Invalid synthesis technique '%s'" % self.synthTech
763 if self.nuqTech
not in [
u'kS21+kS11',
u'kS21',
u'kS21+pole/zero' ]:
764 raise parseError,
u"Invalid Prescribed Insertion Loss technique = '%s'" % self.nuqTech
766 if self.numFreq <= 0:
767 raise parseError,
u"Sweep parameters: Number of samples is not > 0"
769 if self.minFreq >= self.maxFreq:
770 raise parseError,
u"Sweep parameters: Minimum frequency is not smaller than Maximum frequency"
772 if self.minFreq <= 0:
773 raise parseError,
u"Minimum frequency must be larger than 0 Hz"
776 raise parseError,
u"Central frequency must be larger than 0"
779 raise parseError,
u"Bandwidth must be larger than 0"
781 if self.numFreq <= 1:
782 raise parseError,
u"Number of frequency samples must be larger than 1"
784 if self.filterTransferFunc.title() ==
u'Chebyshev' and self.chebyLr <= 0:
785 raise parseError,
u"Chebyshev filter return losses must be larger than 0"
787 if self.filterTransferFunc.title() ==
u'Quasieliptic':
788 if self.qeLr <= 0:
raise parseError,
u"Quasieliptic filter return losses must be larger than 0"
789 if self.qeZero <= 1:
raise parseError,
u"Quasieliptic filter transmission zero must be larger than 1"
792 if self.transImagZeros
is None: self.transImagZeros = [ ]
793 if self.transComplexZeros
is None: self.transComplexZeros = [ ]
794 if self.LPcomplexZeros
is None: self.LPcomplexZeros = [ ]
795 if self.LPrealZeros
is None: self.LPrealZeros = [ ]
796 if self.wFunc
is None: self.wFunc = [ ]
799 if type(self.transImagZeros) != types.ListType: self.transImagZeros = [ self.transImagZeros ]
800 if type(self.transComplexZeros) != types.ListType: self.transComplexZeros = [ self.transComplexZeros ]
801 if type(self.LPcomplexZeros) != types.ListType: self.LPcomplexZeros = [ self.LPcomplexZeros ]
802 if type(self.LPrealZeros) != types.ListType: self.LPrealZeros = [ self.LPrealZeros ]
805 if type(self.LPcomplexZeros).__name__
in [
'int',
'float',
'complex']: self.LPcomplexZeros = [ self.LPcomplexZeros ]
806 if type(self.LPrealZeros).__name__
in [
'int',
'float',
'complex']: self.LPrealZeros = [ self.LPrealZeros ]
808 if self.filterTransferFunc.title() ==
u'Generalized Chebyshev':
809 if self.genChebyLr <= 0:
810 raise parseError,
u"Generalized Chebyshev filter return losses must be larger than 0"
812 if self.genChebyLP
and any( np.real(self.LPcomplexZeros + self.LPrealZeros)==0 ):
813 raise parseError,
'Linear Phase optimization zeros cannot be purely imaginary'
815 if self.genChebyLP
and any( np.imag(self.LPcomplexZeros)<=0 ):
816 raise parseError,
'Imaginary part of Linear Phase optimization complex zeros cannot be negative or 0 Hz'
818 if len(self.transImagZeros)>0
and any(np.array(self.transImagZeros)<=0):
819 raise parseError,
'Imaginary transmission zeros cannot be negative or 0 Hz'
821 if len(self.transComplexZeros)>0
and any(np.imag(self.transComplexZeros) <=0):
822 raise parseError,
'Imaginary part of complex transmission zeros cannot be negative or 0 Hz'
824 if self.synthTech.title() ==
u'Minimum Insertion Loss':
825 if self.finiteQo
and self.Qo <=0:
raise parseError,
u"Q of implementation must be larger than 0"
827 if self.synthTech.title() ==
u'Predistortion':
828 if self.QoPredis <=0:
raise parseError,
u"Predistortion Q of implementation must be larger than 0"
829 if self.Qef <=0:
raise parseError,
u"Predistortion Q to emulate must be larger than 0"
831 if type(self.zerosArrang).__name__ ==
'int' and self.zerosArrang>=1
and self.zerosArrang<=4:
pass
832 elif type(self.zerosArrang).__name__ ==
'list':
833 if len(self.zerosArrang) != self.N:
raise parseError,
u"Length of Predistortion factorization method boolean list is different than filter order"
834 if type(self.zerosArrang[0]).__name__ ==
'bool':
pass
835 elif type(self.zerosArrang[0]).__name__ ==
'int':
836 for n
in range(self.N): self.zerosArrang[n] = bool(self.zerosArrang[n])
837 else:
raise parseError,
u"Predistortion factorization method is not a list of Booleans or integers than can be converted to Booleans"
839 else:
raise parseError,
u"Predistortion factorization method is not an integer in the range [1,4] or a list of Booleans"
841 if self.adapPredis == 1:
842 if len(self.wFunc) != self.N:
raise parseError,
u"Length of adaptive predistortion weights list different than filter order"
844 if self.synthTech.title() ==
u'Prescribed Insertion Loss':
845 if self.nuqTech ==
'kS21+kS11':
846 if self.nuqK11c1 <=0:
raise parseError,
u"Prescribed Insertion Loss k21+kS11: k11 must be larger than 0"
847 if self.nuqK22c1 <=0:
raise parseError,
u"Prescribed Insertion Loss k21+kS11: k22 must be larger than 0"
848 if self.nuqK21c1 <=0:
raise parseError,
u"Prescribed Insertion Loss k21+kS11: k21 must be larger than 0"
849 if self.nuqTech ==
'kS21':
850 if self.nuqK21c2 <=0:
raise parseError,
u"Prescribed Insertion Loss k21: k21 must be larger than 0"
851 if self.nuqTech ==
'kS21+pole/zero':
852 if self.nuqK21c3 <=0:
raise parseError,
u"Prescribed Insertion Loss kS21+pole/zero: k21 must be larger than 0"
853 if self.nuqDelta <= 0:
raise parseError,
u"Prescribed Insertion Loss kS21+pole/zero: Delta must be larger than 0"
855 minDelta = 20 * 10**(-self.nuqK21c3/10) - eps
856 if self.nuqDelta < minDelta:
warningMsg(
"WARNING: Prescribed Insertion Loss kS21+pole/zero:<p>Delta parameter smaller than the<br>minimum recommended value (%.2g)" % minDelta)
867 if self.empty ==
False:
868 for key
in parameterDict.values():
869 command =
"Pcopy.%s = self.%s" % (key, key)
884 if self.empty ==
True:
889 pat = re.compile(
'^.*\[(.+)\].*')
892 for line
in fileTemplate.split(
'\n'):
894 if line.find(
'=') >=0
and not line.startswith(
'#'):
895 key = pat.match(line).groups(0)[0]
896 value = eval(
'self.' + parameterDict[key])
899 if type(value) == types.FloatType
or type(value) == types.ComplexType:
900 value =
complexStr(value, saveSignificantDigits, eng =
True)
901 elif type(value) == types.ListType:
902 value =
', '.join( [
complexStr(val, saveSignificantDigits, eng =
True)
for val
in value ] )
904 if value
is not None:
905 st =
'Inf' if value==np.inf
else unicode(value).strip()
909 if type(value) == types.UnicodeType:
910 line = line + filter(
lambda c: c
not in "[]", st )
912 line = line + filter(
lambda c: c
not in "()[]", st )
915 if platform.system()
in [
'Windows',
'Microsoft',
'Vista' ]:
916 out = out + line +
'\r\n'
917 elif platform.system()
in [
'Linux' ]:
918 out = out + line +
'\n'
920 out = out + line +
'\r'
965 def __init__(self, P, CP, FT, freq = None, checkPassive=True):
966 if CP ==
None:
return
985 self.
freq = np.linspace(P.minFreq, P.maxFreq, P.numFreq)
995 if P.synthTech ==
u'Minimum Insertion Loss':
996 if P.finiteQo: Qo = P.Qo
998 elif P.synthTech ==
u'Predistortion':
1000 elif P.synthTech ==
u'Prescribed Insertion Loss':
1008 self.
sigma = 1 / (Qo * FT.FBW)
1041 self.
fromCharPolys(P, self.
s, CP.Ps, CP.Es, CP.Fs, CP.eps, CP.epsR)
1045 S11max, S21max, S22max = max(abs(self.
S11)), max(abs(self.
S21)), max(abs(self.
S22))
1046 if max([S11max, S21max, S22max]) > 1+epstol:
1047 warningMsg(
"""WARNING: [S] parameters computed from CP are larger than 0 dB at some frequency points<p>
1048 max[S11] = %.2f dB, max[S21] = %.2f dB, max[S22] = %.2f dB
1049 """ % (20*log10(S11max), 20*log10(S21max), 20*log10(S22max)) )
1084 NBW = int( P.numFreq * P.BW/(P.maxFreq - P.minFreq) )
1085 N1 = int(P.numFreq/2 - NBW/4)-1
1086 N2 = int(P.numFreq/2 + NBW/4)+1
1087 coef = np.polyfit(self.
omega[N1:N2], self.
phaseS21[N1:N2], 1)
1161 self.
S11 = (1/epsR) * aFs / aEs
1162 self.
S12 = (1/eps) * aPs / aEs
1165 if P.synthTech.title() ==
u'Prescribed Insertion Loss' and P.nuqTech ==
u'kS21+kS11':
1166 k11 = 10**(-P.nuqK11c1/20.0)
1167 k22 = 10**(-P.nuqK22c1/20.0)
1168 k21 = 10**(-P.nuqK21c1/20.0)
1169 self.
S22 = k22 * ( 1 - (k21/k11)**2 ) + ( k21/k11)**2 * (self.
S11)
1171 self.
S22 = (1/epsR) * (-1)**P.N * aFs.conj() / aEs
1189 groupD = np.real( Es.deriv()(evalS)/Es(evalS) - Ps.deriv()(evalS)/Ps(evalS))
1230 extraNodesS = MatQ.extraNodesS
1231 extraNodesL = MatQ.extraNodesL
1232 nodeScalingFactor = MatQ.nodeScalingFactor
1239 if evalS
is not None:
1242 eval = 1j * self.s.imag
1245 self.
S11M = np.zeros(len(eval), dtype=
'complex128')
1246 self.
S21M = np.zeros(len(eval), dtype=
'complex128')
1247 self.
S22M = np.zeros(len(eval), dtype=
'complex128')
1252 for i
in range(len(eval)):
1254 I = np.diag(np.concatenate((np.zeros(extraNodesS), nodeScalingFactor[extraNodesS:-extraNodesL]**2 , np.zeros(extraNodesL))))
1255 Y = 1j*M + eval[i] * I + np.diag(np.concatenate(([GS], np.zeros(N-2) , [GL])))
1256 condY = max(condY, np.linalg.cond(Y))
1259 Z = np.linalg.inv(Y)
1263 self.
S11M[i]= - (1.-2.*GS*Z[0, 0])
1264 self.
S22M[i]= - (1.-2.*GL*Z[-1, -1])
1268 self.
S21M[i]=-2.*sqrt(GS*GL)*Z[-1, 0]
1271 warningMsg(
"WARNING: Computation of [S] parameters from CM:<p>Condition number of matrix to invert is %.1e.<br>[S] parameter values will be wrong due to lack of precision." % condY)
1275 S11max, S21max, S22max = max(abs(self.
S11M)), max(abs(self.
S21M)), max(abs(self.
S22M))
1276 if max([S11max, S21max, S22max]) > 1+epstol:
1277 warningMsg(
"""WARNING: [S] parameters computed from CM '%s' are larger than 0 dB at some frequency points<p>
1278 max[S11] = %.2f dB, max[S21] = %.2f dB, max[S22] = %.2f dB
1279 """ % (MatQ.name, 20*log10(S11max), 20*log10(S21max), 20*log10(S22max)) )
1314 errorS11dBavg = np.mean(np.abs(20.*np.log10(np.abs(self.
S11)) - 20.*np.log10(np.abs(self.
S11M))))
1315 errorS22dBavg = np.mean(np.abs(20.*np.log10(np.abs(self.
S22)) - 20.*np.log10(np.abs(self.
S22M))))
1316 errorS21dBavg = np.mean(np.abs(20.*np.log10(np.abs(self.
S21)) - 20.*np.log10(np.abs(self.
S21M))))
1346 stErrorCM =
""" Average error in [S] computed from Coupling Matrix vs. [S] computed from Characteristic polynomials:
1347 <blockquote>S<sub>11</sub> error = %.3g dB, S<sub>22</sub> error = %.3g dB, S<sub>21</sub> error = %.3g dB</blockquote>
1348 <blockquote>Group delay mean relative error = %.3e</blockquote>""" % (errorS11dBavg, errorS22dBavg, errorS21dBavg, errorGroupDelay )
1350 maxErrorDB = max([errorS11dBavg, errorS21dBavg])
1351 CM_error = abs( 10** (-maxErrorDB/ 20) - 1 )
1353 return stErrorCM, CM_error
1410 eps = MatQ.parent.matrixElementsEps(
'Energy and power')
1422 G = Zo / (Qi * self.
FBW)
1426 extraNodesS = MatQ.extraNodesS
1427 extraNodesL = MatQ.extraNodesL
1428 nodeScalingFactor = MatQ.nodeScalingFactor
1435 eval = 1j * np.imag(self.
s)
1440 last = N - extraNodesL
1444 energyRes, energyResRev = np.zeros((Nf, Nr)), np.zeros((Nf, Nr))
1445 powerRes, powerResRev = np.zeros((Nf, Nr)), np.zeros((Nf, Nr))
1450 for n
in range(m+1, N):
1453 if np.abs(Gmn) > eps:
1454 powerCoup.append( ( (m, n), Gmn, np.zeros(Nf), np.zeros(Nf) ) )
1459 for n
in range(m+1, N):
1462 if np.abs(Bmn) > eps:
1463 energyCoup.append( ( (m, n), Bmn, np.zeros(Nf), np.zeros(Nf) ) )
1470 I = np.diag(np.concatenate((np.zeros(extraNodesS), nodeScalingFactor[extraNodesS:-extraNodesL]**2 , np.zeros(extraNodesL))))
1471 Z = np.linalg.inv( 1j*M + eval[i] * I + np.diag(np.concatenate(([GS], np.zeros(N-2) , [GL]))) )
1472 condY = max(condY, np.linalg.cond(Z))
1478 V2 = np.abs(V[first:last])**2
1479 Vrev2 = np.abs(Vrev[first:last])**2
1481 powerRes[i, :] = V2 * G/2
1482 powerResRev[i, :] = Vrev2 * G/2
1484 energyRes[i, :] = V2 * Zo / (4*pi*self.
f0*self.
FBW)
1485 energyResRev[i, :] = Vrev2 * Zo / (4*pi*self.
f0*self.
FBW)
1488 for coup
in powerCoup:
1491 coup[2][i] = np.abs(V[m] - V[n])**2 * Gmn / 2
1492 coup[3][i] = np.abs(Vrev[m] - Vrev[n])**2 * Gmn / 2
1495 for coup
in energyCoup:
1498 coup[2][i] = np.abs(V[m] - V[n])**2 * Bmn / (4* 2*pi*self.
freq[i])
1499 coup[3][i] = np.abs(Vrev[m] - Vrev[n])**2 * Bmn / (4* 2*pi*self.
freq[i])
1502 warningMsg(
"""WARNING: Computation of [S] parameters from CM:<p>Condition number of matrix to invert is %.1e.<br>Results will be wrong due to lack of precision.""" % condY)
1521 fileName = P.outDirName
1522 fout = open(fileName +
'.s2p',
'w')
1523 fcsv = open(fileName +
'.csv',
'w')
1524 fd = csv.writer(fcsv, delimiter =
';')
1527 colWidth = 10 + prec
1530 fout.write (
'! [S] parameters file in TouchStone format.\n\n')
1531 fout.write(
'# GHZ S DB R 50\n\n')
1534 fd.writerow([
'[S] parameters'])
1536 st =
'%-*s%-*s%-*s%-*s%-*s%-*s%-*s%-*s%-*s\n' % (colWidth,
' !Freq', colWidth,
' S11(dB)', colWidth,
' S11(ang)', colWidth,
' S12(dB)', colWidth,
' S12(ang)', colWidth,
' S21(dB)', colWidth,
' S21(ang)', colWidth,
' S22(dB)', colWidth,
' S22(ang)' )
1538 fd.writerow([
'Freq(GHz)',
'S11(dB)',
'S11(ang)',
'S12(dB)',
'S12(ang)',
'S21(dB)',
'S21(ang)',
'S22(dB)',
'S22(ang)'])
1541 for n
in range(len(self.
S11)):
1542 freq = str(self.
freq[n] / 1e9)
1547 st +=
'%-*s%-*s%-*s%-*s%-*s\n' % (colWidth, freq, colWidth, S11, colWidth, S21, colWidth, S12, colWidth, S22)
1548 fd.writerow([freq] +
complexStr(self.
S11[n], prec,
'DB', colWidth, listFormat =
True) +
complexStr(self.
S12[n], prec,
'DB', colWidth, listFormat =
True) +
complexStr(self.
S21[n], prec,
'DB', colWidth, listFormat =
True) +
complexStr(self.
S22[n], prec,
'DB', colWidth, listFormat =
True))
1553 myPrint(
"[S] parameters saved to files: %s.s2p and %s.csv" % (fileName, fileName) )
1582 def __init__(self, parent, M, name, extraNodesS, extraNodesL, FT, fileExt = None, nodeScalingFactor=None, flagRotateAllowed = True):
1589 self.
order = np.size(M, 0)
1602 self.
name = unicode(name)
1648 if nodeScalingFactor
is not None:
1742 eps = self.parent.matrixElementsEps()
1748 losses = np.zeros(last - first)
1749 for i
in range(first, last):
1750 losses[i-first] = sum(np.imag(M[:,i]))
1751 if abs(losses[i-first]) < eps:
1752 losses[i-first] = 0.
1756 self.
Q = -1 / (losses * FBW)
1852 eps = self.parent.matrixElementsEps()
1854 N = np.size(self.
M, 1)
1859 alpha = np.matrix(np.ones(N))
1862 alpha[0, 1:N-1] = sqrt( self.FT.FBW*pi/(2*self.
Zo) )
1863 alpha[0, 0] = sqrt(1./self.
ZoS)
1864 alpha[0, N-1] = sqrt(1./self.
ZoL)
1865 self.
Mbp = self.
M * np.array((alpha.T*alpha))
1870 self.
Mcbw = np.zeros((N, N), dtype=complex)
1871 self.
McbwTL = np.zeros((N, N), dtype=complex)
1874 Bn_bp = np.diag(self.
M).real * FBW
1875 fn = self.FT.unormFreq(-np.diag(self.
M).real)
1879 for n
in range(m+1):
1880 if abs(self.
M[m, n]) < eps:
continue
1882 self.
McbwTL[m, n] = (f0/1e6) / self.
Mbp[m, n]
1884 self.
Mcbw[m, n] = self.
M[m, n]**2 * BW / 1e6
1888 self.
McbwTL[n, n] = fn[n] / 1e6
1889 self.
Mcbw[n, n] = fn[n] / 1e6
1891 A = ( fn[n]/fn[m] + fn[m]/fn[n] ) / 2
1892 C = abs( ( (fn2[n]-fn2[m])/(fn2[m]+fn2[m]) )**2 )
1896 self.
McbwTL[m, n] = f0 * np.sqrt( (self.
Mbp[m, n]/A)**2 + C ) / 1e6
1899 if abs(self.
McbwTL[m, n] / (self.
Mbp[m, n]*f0/1e6) + 1) < 1: self.
McbwTL[m, n] = - self.
McbwTL[m, n]
1903 self.
Mcbw[m, n] = self.
M[m, n] * BW / 1e6
1932 M = np.array(self.
M)
1936 raise synthError,
u"It is not allowed to rotate matrix after a Node Scaling in a resonant node with scale factor different from 1 or -1."
1940 for n
in range(0, self.
extraNodesS-1 ): labels.append(
'NR')
1941 labels.extend( [
'R' for elem in range(0, N - self.extraNodesS - self.extraNodesL) ] )
1942 for n
in range(0, self.
extraNodesL-1 ): labels.append(
'NR')
1947 raise synthError,
u"It is not allowed to rotate a matrix with a pivot in the diagonal."
1948 elif labels[i] ==
'S' or labels[j] ==
'S' or labels[i] ==
'L' or labels[j] ==
'L':
1949 raise synthError,
u"It is not allowed to rotate a matrix with a pivot in the S or L rows or columns."
1950 elif labels[i] != labels[j]:
1951 raise synthError,
u"It is not allowed to rotate a matrix with a pivot in a row and column of different resonant/non-resonant type."
1954 if rotationType ==
'trigonometric':
1957 elif rotationType ==
'hyperbolic':
1958 cr = np.cosh(rotAng)
1959 sr = 1j*np.sinh(rotAng)
1961 raise synthError,
u"Wrong rotation type. rotationType should be either 'trigonometric' or 'hyperbolic'."
1964 R = np.diag(np.ones(N)+1j*np.zeros(N))
1971 rotatedM = np.dot(R, np.dot(M, R.T))
2063 if position ==
u'source':
2064 Minflate = np.zeros((N+1, N+1), dtype=
'complex128')
2065 Minflate[1::, 1::] = M
2067 Minflate[0, 1] = Minflate[1, 0] = k
2070 elif position ==
u'load':
2071 Minflate = np.zeros((N+1, N+1), dtype=
'complex128')
2072 Minflate[:-1:, :-1:] = M
2074 Minflate[-1, -2] = Minflate[-2, -1] = k
2077 elif position ==
u'both':
2078 Minflate = np.zeros((N+2, N+2), dtype=
'complex128')
2079 Minflate[1:-1, 1:-1] = M
2081 Minflate[0, 1] = Minflate[1, 0] = k
2083 Minflate[-1, -2] = Minflate[-2, -1] = k
2101 self.
M[:, i] = self.
M[:, i]*b
2102 self.
M[i, :] = self.
M[i, :]*b
2161 if (i<>m) & (i<>n) & (j<>m) & (j<>n):
2163 raise synthError,
u"The element to set to zero [m,n] must be in the row or column of the rotation pivot [i,j] or its transpose [j,i]."
2164 elif (m<>n) & (i==m) & (j<>m) & (j<>n):
2168 elif (m<>n) & (i<>m) & (i<>n) & (j==m):
2171 val = -M[j,k]/M[i,k]
2172 elif (m<>n) & (i==n) & (j<>m) & (j<>n):
2176 elif (m<>n) & (i<>m) & (i<>n) & (j==n):
2179 val = -M[k,j]/M[k,i]
2180 elif (m==n) & (i==m) & (j<>m):
2183 val = (-M[i,j]+np.sqrt(M[i,j]**2-M[i,i]*M[j,j]))/M[j,j]
2185 raise synthError,
u"M[j,j] is equal to zero and therefore this pivot should be changed with another one which is different from zero."
2186 elif (m==n) & (i<>m) & (j==m):
2189 val = (M[i,j]+np.sqrt(M[i,j]**2-M[i,i]*M[j,j]))/M[i,i]
2191 raise synthError,
u"M[i,i] is equal to zero and therefore this pivot should be changed with another one which is different from zero."
2195 val = 2.*M[i,j]/(M[j,j]-M[i,i])
2198 if rotationType ==
'trigonometric':
2199 rotAng = f*np.arctan(val)
2200 elif rotationType ==
'hyperbolic':
2202 rotAng = -1j*f*np.arctan(val)
2204 raise synthError,
u"Wrong rotation type. rotationType should be either 'trigonometric' or 'hyperbolic'."
2217 Geff = 1/(Qeff*self.FT.FBW)
2223 for n
in range(first, last):
2224 M[n, n] = M[n, n].real + 1j * (M[n, n].imag - Geff)
2252 UpperBool = np.fromfunction(
lambda i,j: i<=j, (N, N))
2253 NonZeroReal,NonZeroImag = topologyReal*UpperBool, topologyImag*UpperBool
2257 NonZeroReal[Rindices, Rindices] =
True
2258 NonZeroImag[Rindices, Rindices] =
False
2259 topologySignReal[Rindices, Rindices] = 0
2263 NonZeroReal[NRindices, NRindices] =
False
2264 NonZeroImag[NRindices, NRindices] =
True
2265 topologySignImag[NRindices, NRindices] = -1
2268 signs = np.concatenate([ topologySignReal[NonZeroReal], topologySignImag[NonZeroImag] ])
2271 numReal = len(M[NonZeroReal])
2275 maxAbsElem = 4 * np.max(np.abs(M))
2276 if maxAbsElem < 2: maxAbsElem = 2
2279 for n
in range(len(signs)):
2280 lowerBound, upperBound = -maxAbsElem, maxAbsElem
2281 if signs[n] >0: lowerBound = 0
2282 if signs[n] <0: upperBound = 0
2283 bounds.append( (lowerBound, upperBound) )
2285 x0 = np.concatenate([np.real(M[NonZeroReal]), np.imag(M[NonZeroImag])])
2297 return x0, NonZeroReal, NonZeroImag, numReal, bounds
2318 M = np.zeros((N, N), dtype = complex)
2319 M[NonZeroReal] = NonZeroValues[0:numReal]
2320 M[NonZeroImag] = M[NonZeroImag] + 1j*NonZeroValues[numReal::]
2321 M = M + np.triu(M, 1).T
2324 losses = -1/(Q*self.FT.FBW)
2326 for i
in Rindices: M[i, i] = M[i, i] + 1j * (losses - np.sum(M[:, i].imag))
2432 def uniformQ(self, P, CP, weights, Q, algor, maxIter, Nsamples, S11DR, S21DR, topologyReal, topologyImag, topologySignReal, topologySignImag):
2450 def setupOptimFreq(P, CP, FT, minFreq, maxFreq, Nsamples):
2457 NpassBand = int(Nsamples/2)
2458 Noutband = int((Nsamples+1)/2)
2459 delta = BW/NpassBand
2460 freqInband = np.linspace(f0-BW/2+delta/2, f0+BW/2-delta/2, NpassBand)
2461 freqOutBandLower = np.linspace(minFreq, f0-BW/2, int(Noutband/2) )
2462 freqOutBandUpper = np.linspace(f0+BW/2, maxFreq, int((Noutband+1)/2) )
2463 freq = np.concatenate([freqOutBandLower, freqInband, freqOutBandUpper])
2464 sEval = 1j * FT.normFreq(freq)
2470 x0, NonZeroReal, NonZeroImag, numReal, bounds = self.
setupOptimTopology(topologyReal, topologyImag, topologySignReal, topologySignImag)
2472 SPref = setupOptimFreq(P, CP, self.
FT, P.minFreq, P.maxFreq, Nsamples)
2475 S11min = np.max( 20*np.log10(np.abs(SPref.S11)) ) - S11DR
2476 S21min = np.max( 20*np.log10(np.abs(SPref.S21)) ) - S21DR
2479 args = (SPref, S11min, S21min, NonZeroReal, NonZeroImag, numReal, weights, Q)
2481 print "\nCOUPLING MATRIX OPTIMIZATION:"
2482 if algor ==
'L-BFG-S': NonZeroValues = scop.fmin_l_bfgs_b(self.
uniformQOptimize, x0, fprime=
None, args=args, bounds=bounds, approx_grad=
True, maxfun=maxIter, iprint=1 )[0]
2483 elif algor ==
'TNC': NonZeroValues = scop.fmin_tnc(self.
uniformQOptimize, x0, fprime=
None, args=args, bounds=bounds, approx_grad=
True, maxfun=maxIter )[0]
2484 elif algor ==
'SLSQP': NonZeroValues = scop.fmin_slsqp(self.
uniformQOptimize, x0, fprime=
None, args=args, bounds=bounds, iprint = 2, iter=maxIter)
2485 else:
raise synthError,
"Non valid optimization algorithm %s" % algor
2488 MatQOut = self.
newMatQFromNonZero(NonZeroValues, NonZeroReal, NonZeroImag, numReal, Q)
2489 self.
M = MatQOut.M.copy()
2513 def uniformQOptimize(self, NonZeroValues, SPref, S11min, S21min, NonZeroReal, NonZeroImag, numReal, weights, Q):
2514 weightS11 = weights[0]
2515 weightS22 = weights[1]
2516 weightS21 = weights[2]
2517 weightGD = weights[3]
2520 MatQtest = self.
newMatQFromNonZero(NonZeroValues, NonZeroReal, NonZeroImag, numReal, Q)
2523 SPref.fromCouplingMatrix(MatQtest, checkPassive=
False)
2524 S11 = 20*np.log10(np.abs(SPref.S11))
2525 S11M = 20*np.log10(np.abs(SPref.S11M))
2526 S22 = 20*np.log10(np.abs(SPref.S22))
2527 S22M = 20*np.log10(np.abs(SPref.S22M))
2528 S21 = 20*np.log10(np.abs(SPref.S21))
2529 S21M = 20*np.log10(np.abs(SPref.S21M))
2532 S11[S11 < S11min] = S11min
2533 S11M[S11M < S11min] = S11min
2534 S22[S22 < S11min] = S11min
2535 S22M[S22M < S11min] = S11min
2536 S21[S21 < S21min] = S21min
2537 S21M[S21M < S21min] = S21min
2540 errS11 = np.abs(S11 - S11M)
2541 errS22 = np.abs(S22 - S22M)
2542 errS21 = np.abs( S21 - S21M)
2543 errGD = np.abs( SPref.groupDelay2 - SPref.groupDelayM ) / np.mean(np.abs(SPref.groupDelay2))
2546 goalS11 = np.mean(errS11)
2547 goalS22 = np.mean(errS22)
2548 goalS21 = np.mean(errS21)
2549 goalGD = np.mean(errGD)
2550 goal = weightS11*goalS11 + weightS22*goalS22 + weightS21*goalS21 + weightGD*goalGD
2577 def uniformQMask(self, P, CP, weights, Q, algor, maxIter, Nsamples, SM, topologyReal, topologyImag, topologySignReal, topologySignImag):
2579 x0, NonZeroReal, NonZeroImag, numReal, bounds = self.
setupOptimTopology(topologyReal, topologyImag, topologySignReal, topologySignImag)
2585 SM.specToMask(SPref)
2586 SM.maskSamplesOptimization(self.
FT, Nsamples)
2589 args = (SPref, SM, NonZeroReal, NonZeroImag, numReal, weights, Q)
2591 print "\nCOUPLING MATRIX OPTIMIZATION:"
2592 if algor ==
'L-BFG-S': NonZeroValues = scop.fmin_l_bfgs_b(self.
uniformQOptimizeMask, x0, fprime=
None, args=args, bounds=bounds, approx_grad=
True, maxfun=maxIter, iprint=1 )[0]
2593 elif algor ==
'TNC': NonZeroValues = scop.fmin_tnc(self.
uniformQOptimizeMask, x0, fprime=
None, args=args, bounds=bounds, approx_grad=
True, maxfun=maxIter )[0]
2594 elif algor ==
'SLSQP': NonZeroValues = scop.fmin_slsqp(self.
uniformQOptimizeMask, x0, fprime=
None, args=args, bounds=bounds, iprint = 2, iter=maxIter)
2595 else:
raise synthError,
"Non valid optimization algorithm %s" % algor
2598 MatQOut = self.
newMatQFromNonZero(NonZeroValues, NonZeroReal, NonZeroImag, numReal, Q)
2599 self.
M = MatQOut.M.copy()
2626 weightS11 = weights[0]
2627 weightS22 = weights[1]
2628 weightS21 = weights[2]
2631 MatQtest = self.
newMatQFromNonZero(NonZeroValues, NonZeroReal, NonZeroImag, numReal, Q)
2634 SPref.fromCouplingMatrix(MatQtest, evalS = SM.evalSoptim, checkPassive=
False)
2635 S11M = 20*np.log10(np.abs( SPref.S11M[:SM.NfreqInBandOptim] ))
2636 S22M = 20*np.log10(np.abs( SPref.S22M[:SM.NfreqInBandOptim] ))
2637 S21MinBand = 20*np.log10(np.abs( SPref.S21M[:SM.NfreqInBandOptim] ))
2638 S21MoutBand = 20*np.log10(np.abs( SPref.S21M[SM.NfreqInBandOptim:] ))
2641 errS11 = S11M - SM.S11optim
2642 errS11[errS11<0] = 0
2644 errS22 = S22M - SM.S11optim
2645 errS22[errS22<0] = 0
2647 errS21MinBand = SM.S21inBandOptim - S21MinBand
2648 errS21MinBand[errS21MinBand<0] = 0
2650 errS21MoutBand = S21MoutBand - SM.S21outBandOptim
2651 errS21MoutBand[errS21MoutBand<0] = 0
2653 errS21 = np.concatenate([ errS21MinBand, errS21MoutBand ])
2656 goalS11 = np.mean(errS11)
2657 goalS22 = np.mean(errS22)
2658 goalS21 = np.mean(errS21)
2659 goal = weightS11*goalS11 + weightS22*goalS22 + weightS21*goalS21
2675 def saveMat(self, fileName, P, SP, precCM, precEP):
2677 fout = open(fileName,
'w')
2679 fout.write(
u'# Coupling matrix name\n')
2680 fout.write(
u'Name: %s\n\n' % self.
name)
2681 fout.write(
u'# Number of non-resonant nodes at the source and load sides. Includes the source and load nodes.\n')
2682 fout.write(
u'extraNodesS: %d\n' % self.
extraNodesS)
2683 fout.write(
u'extraNodesL: %d\n\n' % self.
extraNodesL)
2685 fout.write(
u'# Vector with node scaling factors\n')
2686 st =
u"nodeScalingFactor: %s\n\n" % [
"%.4g" % elem
for elem
in self.
nodeScalingFactor]
2687 fout.write(st.replace(
"'",
""))
2689 fout.write(
u'# Flag which indicates if it is allowed to do a matrix rotation (impossible after a resonant node scaling)\n')
2692 fout.write(
u'# Quality factor of resonators\n')
2693 st =
u"Q: %s\n\n" % [
"%.4g" % elem
if abs(elem) != np.inf
else "%s" % str(elem)
for elem
in self.
Q]
2694 fout.write(st.replace(
"'",
""))
2696 fout.write(
u'# Coupling matrix (each line is a matrix row):\n')
2701 SP.energyPowerFromCM(self)
2704 size = self.M.shape[0]
2708 for n
in range(1, first ): labels.append(
'NR' + str(n))
2709 labels.extend( [
'R'+str(elem) for elem in range(1, last-first+1) ] )
2710 for n
in range(first, first+self.
extraNodesL-1 ): labels.append(
'NR' + str(n))
2713 powerRes = SP.powerRes
2714 energyRes = SP.energyRes
2715 powerResTotal = powerRes.sum(axis=1)
2716 energyResTotal = energyRes.sum(axis=1)
2717 powerCoup =SP.powerCoup
2718 energyCoup = SP.energyCoup
2721 colWidth = 10 + precEP
2723 Nf = np.size(energyRes,0)
2724 Nr = np.size(energyRes,1)
2726 fout.write (
'\n# ENERGY AND POWER\n')
2728 fout.write (
'\n# Stored energy in the resonators:\n')
2729 st =
'%-*s' % (colWidth,
'#GHZ')
2730 for n
in range(Nr): st +=
'R%-*d' % (colWidth-1, n+1)
2735 freq = str(SP.freq[m] / 1e9)
2736 st +=
'%-*s' % (colWidth, freq)
2738 stNum =
'%.*g' % (precEP, energyRes[m, n])
2739 st +=
'%-*s' % (colWidth, stNum)
2740 stNum =
'%.*g' % (precEP, energyResTotal[m])
2741 st +=
'%-*s\n' % (colWidth, stNum)
2744 fout.write (
'\n# Dissipated power in the resonators:\n')
2745 st =
'%-*s' % (colWidth,
'#GHZ')
2746 for n
in range(Nr): st +=
'R%-*d' % (colWidth-1, n+1)
2751 freq = str(SP.freq[m] / 1e9)
2752 st +=
'%-*s' % (colWidth, freq)
2754 stNum =
'%.*g' % (precEP, powerRes[m, n])
2755 if stNum ==
'-0': stNum =
'0'
2756 st +=
'%-*s' % (colWidth, stNum)
2757 stNum =
'%.*g' % (precEP, powerResTotal[m])
2758 st +=
'%-*s\n' % (colWidth, stNum)
2761 if len(powerCoup) > 0:
2762 fout.write (
'\n# Dissipated power in the couplings:\n')
2763 st =
'%-*s' % (colWidth,
'#GHZ')
2764 for coup
in powerCoup:
2766 elem =
'%s-%s' % (labels[m], labels[n])
2767 st +=
'%-*s' % ( colWidth, elem)
2772 freq = str(SP.freq[m] / 1e9)
2773 st +=
'%-*s' % (colWidth, freq)
2774 for coup
in powerCoup:
2775 stNum =
'%.*g' % (precEP, coup[2][m])
2776 if stNum ==
'-0': stNum =
'0'
2777 st +=
'%-*s' % (colWidth, stNum)
2794 (mrows, ncols) = M.shape
2798 if (abs(M.real)>10**-prec).any(): colWidth += prec+4
2799 if (abs(M.imag)>10**-prec).any(): colWidth += prec+5
2801 st =
'# ' + self.
name +
u': Low-pass matrix (normalised)\n'
2802 for m
in range(mrows):
2803 for n
in range(ncols):
2805 st +=
u'%-*s' % (colWidth, tmp)
2810 st +=
'\n\n# ' + self.
name +
u': Coupling bandwidth matrix (MHz)\n'
2811 for m
in range(mrows):
2812 for n
in range(ncols):
2814 st +=
u'%-*s' % (colWidth, tmp)
2817 st +=
'\n\n# ' + self.
name +
u': Coupling bandwidth matrix with transmission lines (MHz)\n'
2818 for m
in range(mrows):
2819 for n
in range(ncols):
2821 st +=
u'%-*s' % (colWidth, tmp)
2899 transComplexZeros = np.array(P.transComplexZeros)
2900 transComplexZerosWithSym = np.concatenate((transComplexZeros, -transComplexZeros.conj()))
2901 normImagZeros = [ 1j*elem
for elem
in FT.normFreq(np.array(P.transImagZeros)) ]
2902 normComplexZeros = transComplexZerosWithSym.real + 1j * FT.normFreq(transComplexZerosWithSym.imag)
2903 TZ = np.concatenate(( normImagZeros, normComplexZeros ))
2904 if P.genChebyLP: TZ = np.concatenate([TZ, np.array(P.LPcomplexZeros).real + 1j * FT.normFreq(np.array(P.LPcomplexZeros).imag), -np.conjugate(np.array(P.LPcomplexZeros).real + 1j * FT.normFreq(np.array(P.LPcomplexZeros).imag)), np.array(P.LPrealZeros), -np.array(P.LPrealZeros) ])
2914 cascadedQuartets = self.
fcm2cqs(fCM, 0,
'None')
2931 self.listM.append( tCM)
2932 self.listM.append( fCM )
2933 if CP.flagCase1
or CP.flagCase2
or CP.flagCase3:
2934 self.listM.append( fCM_uniQ )
2935 self.listM.append( arrow )
2936 if culdesac: self.listM.append( culdesac )
2937 if triplet: self.listM.append( triplet )
2938 if cascadedQuartets: self.listM.append( cascadedQuartets )
2939 if pfitzenmaier: self.listM.append( pfitzenmaier )
2940 if inlineAsym: self.listM.append( inlineAsym )
2941 if inlineSym: self.listM.append( inlineSym )
2949 self.
bkpMatQ = [ self.MatQ.copy() ]
2964 if eps < 1e-9: eps = 1e-9
2965 if eps > 1e-5: eps = 1e-5
2968 myPrint(
'Truncation threshold = %.3e for CM_error = %.3e (%s)' % (eps, self.
CM_error, st) )
2982 myPrint(
'Updating CM error estimation %.2e with %.2e (%s)\n' % (self.
CM_error, CM_error, st))
3176 S11n = CP.Fs/CP.epsR
3181 if P.synthTech.title() ==
u'Prescribed Insertion Loss' and P.nuqTech ==
u'kS21+kS11':
3182 k11 = 10**(-P.nuqK11c1/20.0)
3183 k22 = 10**(-P.nuqK22c1/20.0)
3184 k21 = 10**(-P.nuqK21c1/20.0)
3185 S22n = k22 * ( 1- (k21/k11)**2) * Sd + (k21/k11)**2 * S11n
3187 S22n = CP.F22s/CP.epsR
3199 Y22n, error1 = ((Sd+S11n)*(Sd-S22n) + S12n*S21n) / Sd
3200 Y11n, error2 = ((Sd-S11n)*(Sd+S22n) + S12n*S21n) / Sd
3201 Yd, error3 = ((Sd+S11n)*(Sd+S22n) - S12n*S21n) / Sd
3205 if Yd.order != N:
raise synthError,
'Transversal Coupling Matrix computation: Order of Yd(s) different than order of E(s).'
3206 CM_error = abs(np.concatenate( (error1.coef, error2.coef, error3.coef), 1) ).max()
3208 if verbose:
myPrint(
'\nTCM (N+2): error in polinomial division (Y22n, Y11n, Yd) = (%.2e, %.2e, %.2e)' % (abs(error1.coef).max(), abs(error2.coef).max(), abs(error3.coef).max() ))
3211 Y21n = Y21n/Yd.coef[0]
3212 Y22n = Y22n/Yd.coef[0]
3213 Y11n = Y11n/Yd.coef[0]
3217 r22k, p22k, KK22 = sc.signal.residue(Y22n,Yd)
3218 r11k, p11k, KK11 = sc.signal.residue(Y11n,Yd)
3220 r21k, p21k, KK21 = sc.signal.residue(Y21n,Yd)
3228 Kinf = KK21[-1].imag
3236 iLambdak = np.real(lambdak).argsort()
3237 lambdak = lambdak[iLambdak]
3238 TNk = np.sqrt(r22k[iLambdak])
3239 T1k = r21k[iLambdak]/np.sqrt(r22k[iLambdak])
3242 M = 1j*np.zeros((N+2,N+2))
3245 if abs(KK11) <= CM_error: KK11 = np.array([0])
3246 if abs(KK22) <= CM_error: KK22 = np.array([0])
3254 M = M - np.diag(np.concatenate((1j*KK11, lambdak, 1j*KK22), 1))
3261 if (P.synthTech.title() ==
u'Prescribed Insertion Loss')
and (P.nuqTech ==
u'kS21+pole/zero'):
3263 assert CP.nuqDelta
is not None
3273 indDelta = np.argmin( np.abs(np.imag(np.diag(M)) + CP.nuqDelta) )
3274 M = np.delete(np.delete(M.copy(), indDelta, 1), indDelta, 0)
3278 if P.synthTech.title() ==
u'Minimum Insertion Loss' and P.finiteQo:
3280 M[n+1, n+1] += -1j / (P.Qo * FT.FBW)
3282 if P.synthTech.title() ==
u'Predistortion':
3284 M[n+1, n+1] += -1j / (P.QoPredis * FT.FBW)
3288 if verbose:
myPrint(
'TCM (N+2): overall error = %.2e\n' % CM_error)
3290 MatQ =
MatrixQ(self, M,
'Transversal (N+2)', 1, 1, FT, fileExt =
'.tcm')
3295 if np.sign(MatQ.M[1,0]) != np.sign(MatQ.M[1,1]): MatQ.scaleNode(0, -1,
True)
3321 sValues = 1j * np.linspace(-2.0, 2.0, 3*(N+1))
3322 quot = np.poly1d(np.polyfit( sValues, num(sValues)/den(sValues), num.o-den.o ))
3323 error = num - quot*den
3354 Mfcm.setName(
'Folded (N+2)')
3355 Mfcm.setFileExt(
'.fcm')
3360 N = np.size(Mfcm.M,0)
3363 numSteps = (N-3)*(N-2)/2
3368 numColumns = (N-3)/2
3371 numColumns = (N-4)/2
3372 for k
in range(numRows+numColumns):
3376 for l
in range(nerk):
3381 rotAng = Mfcm.rotAngleEliminate(
'trigonometric', i, j, m, n)
3382 Mfcm.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3387 for l
in range(neck):
3392 rotAng = Mfcm.rotAngleEliminate(
'trigonometric', i, j, m, n)
3393 Mfcm.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3408 Marrow = MatQ.copy()
3409 Marrow.setName(
'Arrow (N+2)')
3410 Marrow.setFileExt(
'.arrow')
3413 N = np.size(Marrow.M,0)-2
3415 for i
in range(1, N):
3416 for j
in range(i+1, N+1):
3417 rotAng = Marrow.rotAngleEliminate(
'trigonometric', i, j, i-1, j)
3418 Marrow.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3419 Marrow.Qresonators()
3432 Mtriplet = MatQarrow.copy()
3433 Mtriplet.setName(
'Triplet (N+2)')
3434 Mtriplet.setFileExt(
'.triplet')
3437 N = np.size(Mtriplet.M,0) - 2
3440 for i
in range(numTZ):
3445 rotAng = np.arctan(Mtriplet.M[N-1, N]/(w01+Mtriplet.M[N, N]))
3446 Mtriplet.rotateMatrix(
'trigonometric', N-1, N, rotAng, flagQ=
False)
3447 for j
in range(1, N3+1):
3448 rotAng = Mtriplet.rotAngleEliminate(
'trigonometric', N-j-1, N-j, N-j-1, N-j+1)
3449 Mtriplet.rotateMatrix(
'trigonometric', N-j-1, N-j, rotAng, flagQ=
False)
3453 Mtriplet.Qresonators()
3468 Mculdesac = MatQfcm.copy()
3469 Mculdesac.setName(
'Cul de Sac (N+2)')
3470 Mculdesac.setFileExt(
'.cds')
3473 N = np.size(Mculdesac.M,0) - 2
3476 if N < 5
or numTZ > N-3:
3481 for r
in range(1, R+1):
3484 rotAng = Mculdesac.rotAngleEliminate(
'trigonometric', i, j, i, j-1)
3485 Mculdesac.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3488 for r
in range(1, R+1):
3491 rotAng = Mculdesac.rotAngleEliminate(
'trigonometric', i, j, i, j)
3492 Mculdesac.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3494 Mculdesac.Qresonators()
3509 Mcqs = MatQfcm.copy()
3510 Mcqs.setName(
'Cascaded Quartets (N+2)')
3511 Mcqs.setFileExt(
'.cqs')
3514 N = np.size(Mcqs.M,0) - 2
3524 A = (Mcqs.M[2+R,7+R]*Mcqs.M[3+R,4+R]*Mcqs.M[4+R,5+R]-Mcqs.M[2+R,3+R]*Mcqs.M[5+R,6+R]*Mcqs.M[6+R,7+R]+Mcqs.M[2+R,7+R]*Mcqs.M[3+R,6+R]*Mcqs.M[5+R,6+R])
3525 B = (Mcqs.M[2+R,3+R]*Mcqs.M[3+R,6+R]*Mcqs.M[6+R,7+R]-Mcqs.M[2+R,7+R]*(Mcqs.M[3+R,4+R]**2-Mcqs.M[4+R,5+R]**2-Mcqs.M[5+R,6+R]**2+Mcqs.M[3+R,6+R]**2))
3526 C = -Mcqs.M[2+R,7+R]*(Mcqs.M[3+R,6+R]*Mcqs.M[5+R,6+R]+Mcqs.M[3+R,4+R]*Mcqs.M[4+R,5+R])
3527 rotAng = np.arctan((-B+np.sqrt(B**2-4*A*C))/(2*A))
3528 Mcqs.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3532 rotAng = Mcqs.rotAngleEliminate(
'trigonometric', i, j, 3+R, j)
3533 Mcqs.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3537 rotAng = Mcqs.rotAngleEliminate(
'trigonometric', i, j, 4+R, j)
3538 Mcqs.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3542 rotAng = Mcqs.rotAngleEliminate(
'trigonometric', i, j, i, 5+R)
3543 Mcqs.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3546 if UpDownNone ==
'Up':
3550 rotAng = Mcqs.rotAngleEliminate(
'trigonometric', i, j, i, r+3)
3551 Mcqs.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3552 elif UpDownNone ==
'Down':
3556 rotAng = Mcqs.rotAngleEliminate(
'trigonometric', i, j, r, j)
3557 Mcqs.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3558 elif UpDownNone ==
'None':
3561 raise synthError,
u"Incorrect command. UpDownNone must be 'Up', 'Down' or 'None'."
3576 Mpfi = MatQfcm.copy()
3577 Mpfi.setName(
'Pfitzenmaier (N+2)')
3578 Mpfi.setFileExt(
'.pfi')
3581 N = np.size(Mpfi.M,0) - 2
3584 for r
in range(1, R+1):
3587 rotAng = Mpfi.rotAngleEliminate(
'trigonometric', i, j, i, N-r)
3588 Mpfi.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3603 Minasym = MatQfcm.copy()
3604 Minasym.setName(
'Inline Asymmetric (N+2)')
3605 Minasym.setFileExt(
'.ina')
3608 N = np.size(Minasym.M,0) - 2
3613 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, i, 5)
3614 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3618 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 3, j)
3619 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3622 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, i, 7)
3623 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3626 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 2, j)
3627 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3630 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 4, j)
3631 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3635 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, i, 7)
3636 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3639 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 3, j)
3640 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3643 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 6, j)
3644 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3648 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 4, j)
3649 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3652 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, i, 10)
3653 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3656 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, i, 5)
3657 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3660 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 3, j)
3661 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3664 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 6, j)
3665 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3668 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 5, j)
3669 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3672 rotAng = Minasym.rotAngleEliminate(
'trigonometric', i, j, 8, j)
3673 Minasym.rotateMatrix(
'trigonometric', i, j, rotAng, flagQ=
False)
3675 Minasym.Qresonators()
3689 Minsym = MatQfcm.copy()
3690 Minsym.setName(
'Inline Symmetric (N+2)')
3691 Minsym.setFileExt(
'.ins')
3694 N = np.size(Minsym.M,0) - 2
3697 if (N == 6
and numTZ == 2)
or ((N == 8
or N == 10)
and numTZ == 4)
or (N == 12
and numTZ == 6):
3702 Meven1 = Minsym.copy()
3703 Meven1.M = Meven1.M[1:N/2+1, 1:N/2+1]
3704 Meven1.extraNodesL = Meven1.extraNodesL - 1
3705 Meven1.extraNodesS = Meven1.extraNodesS - 1
3706 Meven2 = Minsym.copy()
3707 Meven2.M = Meven2.M[1:N/2+1, N/2+1:N+1]
3708 Meven2.extraNodesL = Meven2.extraNodesL - 1
3709 Meven2.extraNodesS = Meven2.extraNodesS - 1
3710 Meven = Minsym.copy()
3711 Meven.M = Meven1.M + np.transpose(np.rot90(Meven2.M))
3712 Meven.extraNodesL = Meven.extraNodesL - 1
3713 Meven.extraNodesS = Meven.extraNodesS - 1
3718 rotAng = np.arctan((Minsym.M[2,3]-np.sqrt(((Minsym.M[2,3])**2)-(Minsym.M[2,5]*Minsym.M[3,4])))/Minsym.M[3,4])
3719 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng, flagQ=
False)
3723 rotAng1 = np.arctan((Minsym.M[2,7]*Minsym.M[3,4]-np.sqrt((Minsym.M[2,7]**2)*(Minsym.M[3,4]**2)+(Minsym.M[2,7]*Minsym.M[4,5])*((Minsym.M[2,3]**2)-Minsym.M[2,7]*Minsym.M[3,6])))/(Minsym.M[2,3]**2-Minsym.M[2,7]*Minsym.M[3,6]))
3724 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng1, flagQ=
False)
3727 rotAng2 = np.arctan(Minsym.M[2,7]/(Minsym.M[2,3]*np.sin(rotAng1)))
3728 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng2, flagQ=
False)
3732 rotAng1 = np.arctan((Minsym.M[4,5]-np.sqrt(Minsym.M[4,5]**2-Minsym.M[4,7]*Minsym.M[5,6]))/Minsym.M[5,6])
3733 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng1, flagQ=
False)
3736 rotAng2 = np.arctan((np.sin(rotAng1)*Minsym.M[3,4]-np.sqrt((np.sin(rotAng1)**2*Minsym.M[3,4]**2-Minsym.M[3,8]*(Minsym.M[4,7]+Minsym.M[5,6]))))/(Minsym.M[4,7]+Minsym.M[5,6]))
3737 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng2, flagQ=
False)
3740 rotAng3 = np.arctan(np.tan(rotAng2)*Minsym.M[2,3]/(Minsym.M[4,5]-np.tan(rotAng1)*Minsym.M[5,6]+np.cos(rotAng1)*np.tan(rotAng2)*Minsym.M[3,4]))
3741 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng3, flagQ=
False)
3744 a1 = 2*Minsym.M[4,5]
3745 a2 = Minsym.M[4,9]-((Minsym.M[3,4]**2)/Minsym.M[3,10])
3747 a4 = -2*Minsym.M[5,6]
3748 b0 = Minsym.M[4,9]*Minsym.M[6,7]
3749 b1 = -2*Minsym.M[4,5]*Minsym.M[6,7]
3750 b2 = Minsym.M[5,8]*Minsym.M[6,7]-Minsym.M[5,6]**2
3751 b3 = -2*Minsym.M[5,6]*Minsym.M[4,5]
3752 b4 = Minsym.M[4,9]*Minsym.M[5,8]-Minsym.M[4,5]**2
3753 b5 = 2*Minsym.M[5,6]*Minsym.M[4,9]
3755 c0 = (a0*b4-a3*b0)/c
3756 c1 = (a1*b4-a3*b1)/c
3757 c2 = (a2*b4-a3*b2)/c
3759 d = a2*c3**2+a3*c2**2
3760 d0 = (a0+a3*c0**2+a4*c0)/d
3761 d1 = (a1+2*a0*c3+2*a3*c0*c1+a4*(c1+c0*c3))/d
3762 d2 = (a2+2*a1*c3+a0*c3**2+a3*(c1**2+2*c0*c2)+a4*(c2+c1*c3))/d
3763 d3 = (2*a2*c3+a1*c3**2+2*a3*c1*c2+a4*c2*c3)/d
3764 t1 = np.roots([1., d3, d2, d1, d0])[0]
3767 rotAng1 = np.arctan(t1)
3768 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng1, flagQ=
False)
3771 rotAng2 = np.arctan((c0+c1*t1+c2*t1**2)/((1+c3*t1)*np.sqrt(1+t1**2)))
3772 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng2, flagQ=
False)
3775 rotAng3 = np.arctan(Meven.M[i-1, j-1]/Meven.M[j-1, j-1])
3776 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng3, flagQ=
False)
3779 rotAng4 = np.arctan(Meven.M[i-1, j-1]/Meven.M[j-1, j-1])
3780 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng4, flagQ=
False)
3783 rotAng5 = np.arctan(Meven.M[i-1, j]/Meven.M[j-1, j])
3784 Meven.rotateMatrix(
'trigonometric', i-1, j-1, rotAng5, flagQ=
False)
3786 Minline = np.zeros([N/2,N], dtype=
'complex128')
3788 for i
in range(N/2):
3790 Minline[i,i+1] = Meven.M[i,i+1]
3791 Minline[i+1,i] = Minline[i,i+1]
3793 Minline[i,i+1] = Meven.M[i,i]
3797 Minline[0,3] = Meven.M[0,2]
3798 Minline[2,5] = Minline[0,3]
3800 Minline[0,3] = Meven.M[0,3]
3801 Minline[3,0] = Minline[0,3]
3802 Minline[2,5] = Meven.M[2,2]
3804 Minline[0,3] = Meven.M[0,3]
3805 Minline[3,0] = Minline[0,3]
3806 Minline[2,5] = Meven.M[2,4]
3807 Minline[4,7] = Minline[2,5]
3809 Minline[0,3] = Meven.M[0,3]
3810 Minline[3,0] = Minline[0,3]
3811 Minline[2,5] = Meven.M[2,5]
3812 Minline[4,7] = Meven.M[4,4]
3813 Minline[5,2] = Minline[2,5]
3816 Minline1=np.rot90(Minline)
3817 Minline2=np.rot90(Minline1)
3818 Minsym.M[1:N+1, 1:N+1]=np.concatenate([Minline, Minline2])
3820 Minsym.Qresonators()
3831 file = codecs.open(fileName,
'r', 'utf-8')
3832 except IOError, err:
3833 raise parseError,
'I/O error: %s' % err
3834 stList = file.readlines()
3837 validLines = [ st
for st
in stList
if not st.startswith(
'#')
and not st.isspace() ]
3839 pat = re.compile(
'^Name:(.+)')
3840 name = pat.match(validLines[0]).groups(1)[0].lstrip().rstrip()
3842 pat = re.compile(
'^extraNodesS:(.+)')
3843 extraNodesS = int(pat.match(validLines[1]).groups(1)[0])
3845 pat = re.compile(
'^extraNodesL:(.+)')
3846 extraNodesL = int(pat.match(validLines[2]).groups(1)[0])
3848 pat = re.compile(
'^nodeScalingFactor:(.+)')
3849 nodeScalingFactor = np.array( eval(pat.match(validLines[3]).groups(1)[0].strip()) )
3851 pat = re.compile(
'^flagRotateAllowed:(.+)')
3852 flagRotateAllowed = eval(pat.match(validLines[4]).groups(1)[0].strip())
3855 N = len(nodeScalingFactor)
3858 for line
in validLines[6:6+N]:
3859 Mlist.append([complex(elem)
for elem
in line.split()])
3862 MatQ =
MatrixQ(self, M, name, extraNodesS, extraNodesL, self.
FT, nodeScalingFactor=nodeScalingFactor, flagRotateAllowed=flagRotateAllowed)
3863 myPrint(
"Coupling matrix '%s' read from file: %s" % (name, os.path.basename(fileName)) )
3879 for MatQ
in self.
listM:
3880 if MatQ.fileExt
is None:
continue
3882 st =
" Q of resonators = %s" % [
"%.4g" % elem
if abs(elem) != np.inf
else "%s" % str(elem)
for elem
in MatQ.Q]
3884 fileName = P.outDirName + MatQ.fileExt
3885 MatQ.saveMat(fileName, P, SP, precCM, precEP)
3886 myPrint(
" Matrix saved to file: %s" % fileName)
3905 MatQ = MatQfcm2.copy()
3906 MatQ.setName(
'Folded with uniform Q (N+4)')
3907 MatQ.setFileExt(
'.fcm_uniQ')
3910 MatQ.inflateMatrix(
'both')
3913 A=np.imag(MatQ.M[2, 2])
3917 C=MatQ.M[1, 2]**2 /np.imag(MatQ.M[1, 1])
3920 alpha=0.5*np.log(1./2/(-2*A-C+2*B)*(-2.*C+4.*np.sqrt(-A**2-C*A+B**2)))
3924 MatQ.rotateMatrix(
'hyperbolic',i,j,alpha, flagQ=
False)
3926 MatQ.rotateMatrix(
'hyperbolic',i,j,alpha, flagQ=
False)
3929 h=-np.imag(MatQ.M[3, 1])/np.imag(MatQ.M[1, 1])
3930 MatQ.scaleNode(1, h, flagQ=
False)
3931 h=-np.imag(MatQ.M[4, 6])/np.imag(MatQ.M[6, 6])
3932 MatQ.scaleNode(6, h, flagQ=
True)
3946 MatQ = MatQfcm2.copy()
3947 MatQ.setName(
'Folded with uniform Q (N+4)')
3948 MatQ.setFileExt(
'.fcm_uniQ')
3951 print "\nUNIFORM Q OPTIMIZATION:"
3952 angRotOpt = scop.fmin(self.
uniformQOrder6Optimize, np.array([0,0]), args=(MatQ, 0), xtol=1.e-8, ftol=1.e-8, maxiter=20000, maxfun=20000, full_output=0, disp=
True, retall=0, callback=
None)
3959 MatQ.inflateMatrix(
'both')
3976 MatQfcm2 = MatQfcm2a.copy()
3977 angle12 = angle65 = angRot[0]
3978 angle23 = angle54 = angRot[1]
3981 i=1; j=2; MatQfcm2.rotateMatrix(
'hyperbolic', i, j, angle12, flagQ=
False)
3982 i=6; j=5; MatQfcm2.rotateMatrix(
'hyperbolic', i, j, angle65, flagQ=
False)
3983 i=2; j=3; MatQfcm2.rotateMatrix(
'hyperbolic', i, j, angle23, flagQ=
False)
3984 i=5; j=4; MatQfcm2.rotateMatrix(
'hyperbolic', i, j, angle54, flagQ=
False)
3987 k=-np.imag(MatQfcm2.M[2,0])/np.imag(MatQfcm2.M[0,0])
3988 MatQfcm2.scaleNode( 0, k, flagQ=
False)
3989 MatQfcm2.scaleNode( 7, k, flagQ=
True)
3991 Q = np.array(MatQfcm2.Q)
3993 goal = abs(1/Q[0]-1/Q[1]) + abs(1/Q[1]-1/Q[2]) + abs(1/Q[2]-1/Q[3]) + abs(1/Q[3]-1/Q[4]) + abs(1/Q[4]-1/Q[5])
4009 MatQ = MatQfcm2.copy()
4010 MatQ.setName(
'Folded with uniform Q (N+4)')
4011 MatQ.setFileExt(
'.fcm_uniQ')
4014 print "\nUNIFORM Q OPTIMIZATION:"
4015 angRotOpt = scop.fmin_slsqp(self.
uniformQOrder6Case3Optimize, np.array([0,0, 0, 0]) , eqcons=[], f_eqcons=
None, ieqcons=[], f_ieqcons=
None,bounds = [],
4016 fprime =
None, fprime_eqcons=
None, fprime_ieqcons=
None, args = (MatQ,
False), iter = 20000, acc = 1.0E-10, iprint = 1, full_output = 0)
4023 MatQ.inflateMatrix(
'both')
4039 MatQfcm2 = MatQfcm2a.copy()
4041 angle14 = angRot[0];
4042 angle23 = angRot[1];
4043 angle12 = angRot[2];
4044 angle34 = angRot[3];
4047 i=2; j=5; MatQfcm2.rotateMatrix(
'hyperbolic', i, j, angle14, flagQ=
False)
4048 i=3; j=4; MatQfcm2.rotateMatrix(
'hyperbolic', i, j, angle23, flagQ=
False)
4049 i=2; j=3; MatQfcm2.rotateMatrix(
'hyperbolic', i, j, angle12, flagQ=
False)
4050 i=4; j=5; MatQfcm2.rotateMatrix(
'hyperbolic', i, j, angle34, flagQ=
True)
4054 goal = abs(1/Q[1]-1/Q[2]) + abs(1/Q[2]-1/Q[3]) + abs(1/Q[3]-1/Q[4])
4082 self.
FBW = P.BW/P.f0
4101 return (self.
f0 / self.
BW) * (freq/self.
f0 - self.
f0/freq)
4130 return (self.
f0/2) * (wp + np.sqrt(wp**2 +4))
4145 return groupDelay * (1 + (self.
f0/freq)**2) / (2*pi*self.
BW)
4158 return groupDelay * (2*pi*self.
BW) / 2